//
// exploitable.h
//
// Definitions, Data Declarations, and Function Headers for the !exploitable Crash Analyzer
//
//
// Developed by the Microsoft Security Engineering Center (MSEC)
// Copyright 2008-2013, Microsoft Corporation
//
//	Microsoft Public License (Ms-PL)
//	This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
//
//	Definitions
//		The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. A "contribution" is the original software, or any additions or changes to the software. A "contributor" is any person that distributes its contribution under this license. "Licensed patents" are a contributor's patent claims that read directly on its contribution.
//	Grant of Rights
//		(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
//		(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
//	Conditions and Limitations
//		(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 
//		(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 
//		(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 
//		(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 
//		(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees, or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
//


#pragma once

#include "debugger.h"
#include "metainstructions.h"
#include "msecver.h"
#include <string.h>

#define FAULTING_LOCATION_STRING_LENGTH		512
#define FAULTING_FILE_STRING_LENGTH		512
#define GENERATED_DESCRIPTION_LENGTH	512

#define ACCESS_VIOLATION_TYPE_READ		0
#define ACCESS_VIOLATION_TYPE_WRITE		1
#define ACCESS_VIOLATION_TYPE_DEP		8

#ifndef STATUS_STACK_BUFFER_OVERRUN
#define STATUS_STACK_BUFFER_OVERRUN      ((DWORD)0xC0000409L)
#endif
#define STATUS_WX86_BREAKPOINT           ((DWORD)0x4000001FL)
#define STATUS_HEAP_CORRUPTION			 ((DWORD)0xc0000374L)
#define STATUS_WAKE_SYSTEM_DEBUGGER      ((DWORD)0x80000007L)
#define STATUS_VERIFIER_STOP             ((DWORD)0xC0000421L)

typedef enum _CLASSIFICATION
{
	NOT_AN_EXCEPTION = 0,
	NOT_LIKELY_EXPLOITABLE = 1,
	UNKNOWN = 2,
	PROBABLY_EXPLOITABLE = 3,
	EXPLOITABLE = 4
} CLASSIFICATION;

typedef enum _LOGGING_MODE
{
	NONE = 0,
	HUMAN_NORMAL = 5,
	HUMAN_VERBOSE = 9,
	MACHINE_NORMAL = 6,
	MACHINE_VERBOSE = 10
} LOGGING_MODE;


typedef enum _LOGGING_TYPE
{
	HUMAN = 1,
	MACHINE = 2
} LOGGING_TYPE;

typedef enum _LOGGING_LEVEL
{
	TERSE = 4,
	VERBOSE = 8
} LOGGING_LEVEL;

typedef struct _DECODE_TRAP
{
	PWCHAR name;
	DWORD code;
} DECODE_TRAP;

///
/// Encapsulation of the resolved debugging state. This is filled in during the analysis process
///
typedef struct _DEBUGGER_STATE
{
	_DEBUGGER_STATE()
	{
		dwEventType = DEBUG_EVENT_SYSTEM_ERROR;
		dwProcessId = 0xffffffff;
		dwThreadId = 0xffffffff;
		dwDebugClass = DEBUG_CLASS_UNINITIALIZED;
		dwDebugQualifier = DEBUG_USER_WINDOWS_PROCESS;
		offThreadStackBase = 0;
		offThreadStackLimit = 0;
		qwExceptionSubtype = 0;
		fApplicationVerifierStopDetected = false;
		fExceptionLoaded = false;
		fExceptionAddressInUserMode = false;
		fExceptionAddressNearNull = false;
		fBugCheckDetected = false;
		offFaultingAddress = 0;
		offInstruction = 0;
		pwzIdentity = NULL;
		fExceptionChainCorruptionDetected = false;
		pStack = NULL;
		cStackFrames = 0;
		iInvokingStackFrame = -1;
		pfExcludedStackFrames = NULL;
		pfUnknownStackFrames = NULL;
		dwMajorHash = 0;
		dwMinorHash = 0;
		fStackContainsUnknownSymbols = false;
		wcscpy_s( pwzFaultingLocation, FAULTING_LOCATION_STRING_LENGTH, L"Undetermined Location" );
		fSourceInformationAvailable = false;
		wcscpy_s( pwzFaultingFile, FAULTING_FILE_STRING_LENGTH, L"No Source File Found" );
		dwFaultingLine = 0;
	}

	virtual ~_DEBUGGER_STATE()
	{
		if( pwzIdentity != NULL )
		{
			free( pwzIdentity );
			pwzIdentity = NULL;
		}

		if( pStack != NULL )
		{
			delete[] pStack;
			pStack = NULL;
			cStackFrames = 0;
		}

		if( pfExcludedStackFrames !=  NULL )
		{
			delete[] pfExcludedStackFrames;
			pfExcludedStackFrames = NULL;
		}


		if( pfUnknownStackFrames !=  NULL )
		{
			delete[] pfUnknownStackFrames;
			pfUnknownStackFrames = NULL;
		}

		for( INSTRUCTION_LIST::iterator itIndex = objSourceCode.begin(); itIndex != objSourceCode.end(); itIndex++ )
		{
			if( *itIndex != NULL )
			{
				delete *itIndex;
				*itIndex = NULL;
			}
		}

		setProcessorFlags.clear();
	}

	// Process Information
	ULONG  dwProcessId;
	ULONG  dwThreadId;
	ULONG  dwDebugClass;
	ULONG  dwDebugQualifier;
	ULONG  dwProcessor;
	ULONG  dwActualProcessor;
	PWCHAR pwzIdentity;

	// Thread Information
	ULONG64	offThreadStackBase;
	ULONG64	offThreadStackLimit;

	// Event Information
	ULONG  dwEventType;
	DEBUG_LAST_EVENT_INFO_EXCEPTION objException;
	ULONG64	qwExceptionSubtype;
	bool	fApplicationVerifierStopDetected;
	bool	fExceptionLoaded;
	bool	fExceptionAddressInUserMode;
	bool	fExceptionAddressNearNull;
	bool	fBugCheckDetected;
	ULONG64 offFaultingAddress;

	// State information
	bool	fExceptionChainCorruptionDetected;

	// Stack Information
	PDEBUG_STACK_FRAME pStack;
	bool *	pfExcludedStackFrames;
	bool *	pfUnknownStackFrames;
	ULONG	cStackFrames;
	ULONG	dwMajorHash;
	ULONG	dwMinorHash;
	LONG	iInvokingStackFrame;
	WCHAR	pwzFaultingLocation[FAULTING_LOCATION_STRING_LENGTH];
	bool	fSourceInformationAvailable;
	WCHAR	pwzFaultingFile[FAULTING_FILE_STRING_LENGTH];
	ULONG	dwFaultingLine;
	bool	fStackContainsUnknownSymbols;
	ULONG64	offInstruction;

	// Code Information
	INSTRUCTION_LIST	objSourceCode;
	OPERAND_SET			setProcessorFlags;
} DEBUGGER_STATE;


#ifdef EXPLOITABLE_MODULE

///
// Internal tables
///
PCWSTR CLASSIFICATION_TABLE[] = 
{
	L"NOT_AN_EXCEPTION",
	L"PROBABLY_NOT_EXPLOITABLE",
	L"UNKNOWN",
	L"PROBABLY_EXPLOITABLE",
	L"EXPLOITABLE"
};

PCWSTR METAINSTRUCTION_TABLE[] = 
{
	L"UNKNOWN_INSTRUCTION",
	L"BRANCH",
	L"RETURN",
	L"UNPREDICTABLE_CONDITIONAL_EXECUTION",
	L"INTERRUPT",
	L"DATA_MOVE",
	L"DATA_EXCHANGE",
	L"BLOCK_DATA_MOVE",
	L"STACK_PUSH",
	L"STACK_POP",
	L"CALCULATION",
	L"NOOP",
	L"NONDISASSEMBLE_INSTRUCTION"
};

_DECODE_TRAP TRAP_DECODE_MAP[] =
{
	{L"STATUS_WAIT_0",			(DWORD)0x00000000L},
	{L"STATUS_ABANDONED_WAIT_0", (DWORD)0x00000080L},
	{L"STATUS_USER_APC",			(DWORD)0x000000C0L},
	{L"STATUS_TIMEOUT",			(DWORD)0x00000102L},
	{L"STATUS_PENDING",          (DWORD)0x00000103L},    
	{L"DBG_EXCEPTION_HANDLED",   (DWORD)0x00010001L},
	{L"DBG_CONTINUE",			(DWORD)0x00010002L},
	{L"STATUS_SEGMENT_NOTIFICATION",	(DWORD)0x40000005L},
    {L"DBG_TERMINATE_THREAD",  (DWORD)0x40010003L},    
    {L"DBG_TERMINATE_PROCESS",  (DWORD)0x40010004L},    
    {L"DBG_CONTROL_C",  (DWORD)0x40010005L},    
    {L"DBG_CONTROL_BREAK",  (DWORD)0x40010008L},    
    {L"DBG_COMMAND_EXCEPTION",  (DWORD)0x40010009L},    
    {L"STATUS_GUARD_PAGE_VIOLATION",  (DWORD)0x80000001L},    
    {L"STATUS_DATATYPE_MISALIGNMENT",  (DWORD)0x80000002L},    
    {L"STATUS_BREAKPOINT",  (DWORD)0x80000003L},
    {L"STATUS_SINGLE_STEP",  (DWORD)0x80000004L},    
    {L"DBG_EXCEPTION_NOT_HANDLED",  (DWORD)0x80010001L},    
    {L"STATUS_ACCESS_VIOLATION",  (DWORD)0xC0000005L},    
    {L"STATUS_IN_PAGE_ERROR",  (DWORD)0xC0000006L},    
    {L"STATUS_INVALID_HANDLE",  (DWORD)0xC0000008L},    
    {L"STATUS_NO_MEMORY",  (DWORD)0xC0000017L},    
    {L"STATUS_ILLEGAL_INSTRUCTION",  (DWORD)0xC000001DL},    
    {L"STATUS_NONCONTINUABLE_EXCEPTION",  (DWORD)0xC0000025L},    
    {L"STATUS_INVALID_DISPOSITION",  (DWORD)0xC0000026L},    
    {L"STATUS_ARRAY_BOUNDS_EXCEEDED",  (DWORD)0xC000008CL},    
    {L"STATUS_FLOAT_DENORMAL_OPERAND",  (DWORD)0xC000008DL},    
    {L"STATUS_FLOAT_DIVIDE_BY_ZERO",  (DWORD)0xC000008EL},    
    {L"STATUS_FLOAT_INEXACT_RESULT",  (DWORD)0xC000008FL},    
    {L"STATUS_FLOAT_INVALID_OPERATION",  (DWORD)0xC0000090L},    
    {L"STATUS_FLOAT_OVERFLOW",  (DWORD)0xC0000091L},    
    {L"STATUS_FLOAT_STACK_CHECK",  (DWORD)0xC0000092L},    
    {L"STATUS_FLOAT_UNDERFLOW",  (DWORD)0xC0000093L},    
    {L"STATUS_INTEGER_DIVIDE_BY_ZERO",  (DWORD)0xC0000094L},    
    {L"STATUS_INTEGER_OVERFLOW",  (DWORD)0xC0000095L},    
    {L"STATUS_PRIVILEGED_INSTRUCTION",  (DWORD)0xC0000096L},    
    {L"STATUS_STACK_OVERFLOW",  (DWORD)0xC00000FDL},    
    {L"STATUS_CONTROL_C_EXIT",  (DWORD)0xC000013AL},    
    {L"STATUS_FLOAT_MULTIPLE_FAULTS",  (DWORD)0xC00002B4L},    
    {L"STATUS_FLOAT_MULTIPLE_TRAPS",  (DWORD)0xC00002B5L},    
    {L"STATUS_REG_NAT_CONSUMPTION",  (DWORD)0xC00002C9L},    
    {L"STATUS_SXS_EARLY_DEACTIVATION",  (DWORD)0xC015000FL},    
    {L"STATUS_SXS_INVALID_DEACTIVATION",	(DWORD)0xC0150010L},
	{L"STATUS_CLR_EXCEPTION", (DWORD)0xE0434f4D},
	{L"STATUS_CPP_EH_EXCEPTION", (DWORD)0xE06D7363},
	{L"STATUS_STACK_BUFFER_OVERRUN", (DWORD) 0xC0000409L},
	{L"STATUS_WX86_BREAKPOINT", (DWORD) 0x4000001FL},
	{L"STATUS_HEAP_CORRUPTION", (DWORD) 0xc0000374L},
	{L"STATUS_WAKE_SYSTEM_DEBUGGER", (DWORD) 0x80000007L},
	{L"STATUS_VERIFIER_STOP", (DWORD) 0xC0000421L},
	{NULL, 0}
};

_DECODE_TRAP EXCEPTION_NAME_DECODE_MAP[] = 
{
    {L"Guard Page Violation",  (DWORD)0x80000001L},    
    {L"Data Misalignment",  (DWORD)0x80000002L},    
    {L"Breakpoint",  (DWORD)0x80000003L},    
    {L"In Page Error",  (DWORD)0xC0000006L},    
    {L"Invalid Handle",  (DWORD)0xC0000008L},    
    {L"Out Of Memory",  (DWORD)0xC0000017L},    
    {L"Illegal Instruction",  (DWORD)0xC000001DL},    
    {L"Array Index Out Of Bounds",  (DWORD)0xC000008CL},    
    {L"Floating Point Error",  (DWORD)0xC000008DL},    
    {L"Floating Point Error",  (DWORD)0xC000008EL},    
    {L"Floating Point Error",  (DWORD)0xC000008FL},    
    {L"Floating Point Error",  (DWORD)0xC0000090L},    
    {L"Floating Point Error",  (DWORD)0xC0000091L},    
    {L"Floating Point Error",  (DWORD)0xC0000092L},    
    {L"Floating Point Error",  (DWORD)0xC0000093L},    
    {L"Divide By Zero",  (DWORD)0xC0000094L},    
    {L"Integer Overflow",  (DWORD)0xC0000095L},    
    {L"Privileged Instruction",  (DWORD)0xC0000096L},    
    {L"Stack Exhaustion",  (DWORD)0xC00000FDL},    
    {L"Floating Point Error",  (DWORD)0xC00002B4L},    
    {L"Floating Point Error",  (DWORD)0xC00002B5L},    
	{L"Stack Buffer Overrun", (DWORD) 0xC0000409L},
	{L"WOW64 Breakpoint", (DWORD) 0x4000001FL},
	{L"Heap Corruption", (DWORD) 0xc0000374L},
	{L"Debugger Wake", (DWORD) 0x80000007L},
	{L"Application Verifier Stop", (DWORD) 0xC0000421L},
	{NULL, 0}
};

_DECODE_TRAP SHORT_EXCEPTION_NAME_DECODE_MAP[] = 
{
    {L"GuardPage",  (DWORD)0x80000001L},    
    {L"DataMisalignment",  (DWORD)0x80000002L},    
    {L"Breakpoint",  (DWORD)0x80000003L},    
    {L"InPageError",  (DWORD)0xC0000006L},    
    {L"InvalidHandle",  (DWORD)0xC0000008L},    
    {L"OutOfMemory",  (DWORD)0xC0000017L},    
    {L"IllegalInstruction",  (DWORD)0xC000001DL},    
    {L"ArrayIndexOOB",  (DWORD)0xC000008CL},    
    {L"FPError",  (DWORD)0xC000008DL},    
    {L"FPError",  (DWORD)0xC000008EL},    
    {L"FPError",  (DWORD)0xC000008FL},    
    {L"FPError",  (DWORD)0xC0000090L},    
    {L"FPError",  (DWORD)0xC0000091L},    
    {L"FPError",  (DWORD)0xC0000092L},    
    {L"FPError",  (DWORD)0xC0000093L},    
    {L"DivideByZero",  (DWORD)0xC0000094L},    
    {L"IntegerOverflow",  (DWORD)0xC0000095L},    
    {L"PrivilegedInstruction",  (DWORD)0xC0000096L},    
    {L"StackOverflow",  (DWORD)0xC00000FDL},    
    {L"FPError",  (DWORD)0xC00002B4L},    
    {L"FPError",  (DWORD)0xC00002B5L},    
	{L"GSViolation", (DWORD) 0xC0000409L},
	{L"WOW64Breakpoint", (DWORD) 0x4000001FL},
	{L"HeapCorruption", (DWORD) 0xc0000374L},
	{L"DebuggerWake", (DWORD) 0x80000007L},
	{L"AppVerifierStop", (DWORD) 0xC0000421L},
	{NULL, 0}
};


///
// Internal Functions
///

void SetFaultingInstructionInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState, UINT64 offInstruction );
bool FindUserModeExceptionInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );
bool FindKernelModeExceptionInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );
bool FindExceptionInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );
bool LoadContextRecordFromPointer( const DEBUGGER_CONTROLS &objControls, ULONG64 offRecordPointer );
void LoadContextRecord( const DEBUGGER_CONTROLS &objControls, ULONG64 offRecordPointer );
bool LoadTrapRecordFromPointer( const DEBUGGER_CONTROLS &objControls, ULONG64 offRecordPointer );
void LoadTrapRecord( const DEBUGGER_CONTROLS &objControls, ULONG64 offTrapRecord );
bool LoadExceptionRecordFromPointer( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState, ULONG64 offRecordPointer );
bool LoadExceptionRecord( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState, ULONG64 offRecordPointer );
bool GatherTEB32Address( const DEBUGGER_CONTROLS &objControls, PULONG64  pTEB32RecordAddress);
void ClearStackInformation( __in DEBUGGER_STATE *pState );
bool ParseExploitableArguments( PCSTR pszArguments );
bool ParseMetaDisArguments( PCSTR pszArguments );
void LogStackInformation( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );
void RestoreDebuggerState( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );


#endif


///
// Logging Functions
///

void SetLoggingMode( _LOGGING_MODE eMode );

void SetHashingMode( _HASHING_MODE eMode );

void Log( __in PDEBUG_CONTROL4 pDebugger, LOGGING_LEVEL eLevel, LOGGING_TYPE eType, __in const WCHAR *pwzFormat, ... );

void Log( __in PDEBUG_CONTROL4 pDebugger, LOGGING_TYPE eType, __in const WCHAR *pwzFormat, ... );

void Log( __in PDEBUG_CONTROL4 pDebugger, LOGGING_LEVEL eLevel, LOGGING_TYPE eType, __in const WCHAR *pwzFormat, va_list va );

void LogOperandSet( __in PDEBUG_CONTROL4 pDebugger, __in const WCHAR *pwzHumanPrefix, __in const WCHAR *pwzMachinePrefix, __in const OPERAND_SET& setOperands );


///
// Gather Functions
///

bool GatherInitialState( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherStackInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherExceptionInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherExceptionChainInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherHashInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherProcessorFlags( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherFaultingInstruction( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherExceptionOverridesBasedOnFaultingInstruction( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherBasicBlock( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

bool GatherTaintInformation( const DEBUGGER_CONTROLS &objControls, __in DEBUGGER_STATE *pState );

///
// Report Procedures
///

void ReportInitialState( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );

void ReportExceptionInformation( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );

void ReportFaultingInstruction( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );

void ReportBasicBlock( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );

void ReportBasicBlockDetails( const DEBUGGER_CONTROLS &objControls, const DEBUGGER_STATE &objState );

///
// Analysis Functions
///

bool IsEventNotAnException( const DEBUGGER_STATE &objState );

bool IsFaultingAddressInstructionPointer( const DEBUGGER_STATE &objState );

bool IsFaultingInstructionOnStack( const DEBUGGER_STATE &objState );

bool IsFaultingInstructionInUserland( const DEBUGGER_STATE &objState );

bool CanFaultingInstructionNotBeDisassebled( const DEBUGGER_STATE &objState );

bool IsFaultingInstructionControlFlow( const DEBUGGER_STATE &objState );

bool IsFaultingInstructionBlockDataMove( const DEBUGGER_STATE &objState );

bool IsTaintedDataUsedToDetermineBranchSelection( const DEBUGGER_STATE &objState );

bool IsTaintedDataUsedToDetermineBranchTarget( const DEBUGGER_STATE &objState );

bool IsTaintedDataUsedAsAFunctionArgument( const DEBUGGER_STATE &objState );

bool IsTaintedDataUsedInALaterWrite( const DEBUGGER_STATE &objState );

bool IsTaintedDataUsedAsSourceForBlockDataMove( const DEBUGGER_STATE &objState );

bool IsTaintedDataUsedAsAFunctionRetVal( const DEBUGGER_STATE &objState );

bool DoesStackTraceContainUnknownFunctions( const DEBUGGER_STATE &objState );

bool WasBugCheckDetected( const DEBUGGER_STATE &objState );

bool WasExceptionHandlerChainCorrupted( const DEBUGGER_STATE &objState );

bool WasApplicationVerifierStopDetected( const DEBUGGER_STATE &objState );



